package com.adcc.ags.gms.gw.service;


import com.adcc.ags.gms.core.entity.GWLogLevel;
import com.adcc.ags.gms.core.util.CommonUtil;
import com.adcc.ags.gms.core.util.Constant;
import com.adcc.ags.gms.core.util.LogFactory;
import com.adcc.ags.gms.core.util.MQFactory;
import com.adcc.ags.gms.gw.entity.UserMonitor;
import com.adcc.ags.gms.gw.mapper.UserMonitorMapper;
import com.adcc.ags.gms.gw.vo.UserMonitorVO;
import com.adcc.ags.gms.mq.service.QueueService;
import com.adcc.ags.gms.user.entity.GWUser;
import com.adcc.ags.gms.user.mapper.GWUserMapper;
import com.adcc.utility.log.Log;
import com.adcc.utility.mq.entity.*;
import com.adcc.utility.mq.manager.MQManager;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Optional;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.Queue;

/**
 * 用户监控服务实现层
 */
@Service("UserMonitorService")
public class UserMonitorServiceImpl implements UserMonitorService {

    @Autowired
    private UserMonitorMapper userMonitorMapper;
    //后加
    @Autowired
    private GWUserMapper gwUserMapper;
    @Autowired
    private QueueService queueService;
    @Autowired
    private MQFactory mqFactory;
    @Autowired
    private SysConfigurationService sysConfigurationService;
    @Autowired
    private LogFactory log;
    //用户状态集合
    private static Map<String, Integer> userStates = new HashMap<>();

    @Override
    public Optional<Long> getUserCount() {
        try {
            return Optional.of(userMonitorMapper.getCount());
        } catch (Exception ex) {
            Log.error(UserMonitorService.class.getName() + "getUserCount() error", ex);
            return Optional.absent();
        }
    }

    @Override
    public Optional<Boolean> saveUser(UserMonitor userMonitor) {
        try {
            userMonitorMapper.insert(userMonitor);
            return Optional.of(true);
        } catch (Exception ex) {
            Log.error(UserMonitorService.class.getName(), "saveUser() error", ex);
            return Optional.absent();
        }
    }

    @Override
    public Optional<Boolean> deleteALLUser() {
        try {
            userMonitorMapper.deleteALL();
            return Optional.of(true);
        } catch (Exception ex) {
            Log.error(UserMonitorService.class.getName() + "deleteALLUser() error", ex);
            return Optional.absent();
        }
    }


    /**
     * 获取所有用户监控（四种状态）
     * 2016-12-22 liuyi更新
     *
     * @return
     */
    @Override
    public Optional<List<UserMonitorVO>> findAllUserMonitor() {
        Map<String, Integer> userStatesMap = new HashMap<>();
        try {
            //获取所有的用户配置
            List<GWUser> gwUserList = gwUserMapper.findAllGWUser();
            //获取CGW用户状态
            Map<String, Object> result = getCGWUserStates();
            //结果集
            List<UserMonitorVO> userMonitorVOs = new ArrayList<>();
            if (result != null) {
                List<UserMonitorVO> CGWUsers = (List<UserMonitorVO>) result.get("cgwUserSates");
                //普通模式
                if ("NORMAL".equals(result.get("mode").toString())) {
                    if (gwUserList != null && gwUserList.size() > 0) {
                        for (GWUser gwUser : gwUserList) {
                            UserMonitorVO userMonitorVO = normalMode(gwUser, CGWUsers);
                            userMonitorVOs.add(userMonitorVO);
                            //日志记录
                            userLogRecord(userMonitorVO);
                            userStatesMap.put(userMonitorVO.getName(), userMonitorVO.getState());
                        }
                    }
                } else if ("EMERGENCY".equals(result.get("mode").toString())) {//应急模式
                    List<GWUser> delGwUserList = new ArrayList<>();
                    //过滤库中与rest匹配的用户(不显示rest中与库里没有匹配到的用户)
                    for (UserMonitorVO emergUser : CGWUsers) {
                        UserMonitorVO userMonitorVO = null;
                        for (GWUser gwUser : gwUserList) {
                            if (emergUser.getUserId().equals(gwUser.getUserId())) {
                                userMonitorVO = emergencyMode(emergUser, gwUser);
                                userMonitorVOs.add(userMonitorVO);
                                //日志记录
                                userLogRecord(userMonitorVO);
                                userStatesMap.put(userMonitorVO.getName(), userMonitorVO.getState());
                                //将库中匹配到的用户加入移除集合
                                delGwUserList.add(gwUser);
                                break;
                            }
                        }
                    }
                    //移除库中所有与rest匹配的用户
                    gwUserList.removeAll(delGwUserList);
                    for (GWUser gwUser : gwUserList) {
                        UserMonitorVO userMonitorVO = emergencyMode(null, gwUser);
                        userMonitorVOs.add(userMonitorVO);
                        //日志记录
                        userLogRecord(userMonitorVO);
                        userStatesMap.put(userMonitorVO.getName(), userMonitorVO.getState());
                    }
                }
            } else {//CGW服务异常
                for (GWUser gwUser : gwUserList) {
                    UserMonitorVO userMonitorVO = emergencyMode(null, gwUser);
                    userMonitorVOs.add(userMonitorVO);
                    //日志记录
                    userLogRecord(userMonitorVO);
                    userStatesMap.put(userMonitorVO.getName(), userMonitorVO.getState());
                }
            }
            //更新上一次用户状态集合
            userStates = userStatesMap;
            return Optional.of(userMonitorVOSort(userMonitorVOs));
        } catch (Exception e) {
            log.error(UserMonitorService.class,"用户监控", GWLogLevel.SERIOUS_ALARM, "获取用户监控信息异常");
            return Optional.absent();
        }
    }

    /**
     * 用户状态切换日志记录
     *
     * @param userMonitorVO
     */
    public void userLogRecord(UserMonitorVO userMonitorVO) {
        //上一次用户状态
        Integer lastTimeState = null;
        //新的用户状态
        Integer thisTimeState = userMonitorVO.getState();
        try {
            if ((lastTimeState = userStates.get(userMonitorVO.getName())) != null) {

                //比较两种状态记录日志
                switch (lastTimeState) {
                    case 1://红
                        switch (thisTimeState) {
                            case 1:
                                log.error(UserMonitorService.class, userMonitorVO.getName(), GWLogLevel.ALARM, "监控用户：" + userMonitorVO.getName() + "掉线");
                                break;
                            case 2:
                                log.warn(UserMonitorService.class, userMonitorVO.getName(), "监控用户：" + userMonitorVO.getName() + "队列深度异常");
                                break;
                            case 3:
                                log.info(UserMonitorService.class, userMonitorVO.getName(), "监控用户：" + userMonitorVO.getName() + "上线");
                                break;
                            case 4:
                                log.info(UserMonitorService.class, userMonitorVO.getName(), "监控用户：" + userMonitorVO.getName() + "下线");
                                break;
                        }
                        break;
                    case 2://黄
                        switch (thisTimeState) {
                            case 1:
                                log.error(UserMonitorService.class, userMonitorVO.getName(), GWLogLevel.ALARM, "监控用户：" + userMonitorVO.getName() + "掉线");
                                break;
                            case 2:
                                log.warn(UserMonitorService.class, userMonitorVO.getName(), "监控用户：" + userMonitorVO.getName() + "队列深度异常");
                                break;
                            case 3:
                                //待定
                                break;
                            case 4:
                                log.info(UserMonitorService.class, userMonitorVO.getName(), "监控用户：" + userMonitorVO.getName() + "下线");
                                break;
                        }
                        break;
                    case 3://绿
                        switch (thisTimeState) {
                            case 1:
                                log.error(UserMonitorService.class, userMonitorVO.getName(), GWLogLevel.ALARM, "监控用户：" + userMonitorVO.getName() + "掉线");
                                break;
                            case 2:
                                log.warn(UserMonitorService.class, userMonitorVO.getName(), "监控用户：" + userMonitorVO.getName() + "队列深度异常");
                                break;
                            case 4:
                                log.info(UserMonitorService.class, userMonitorVO.getName(), "监控用户：" + userMonitorVO.getName() + "下线");
                                break;
                        }
                        break;
                    case 4://灰
                        break;
                }

            } else {
                switch (thisTimeState) {
                    case 1:
                        log.error(UserMonitorService.class, userMonitorVO.getName(), GWLogLevel.ALARM, "监控用户：" + userMonitorVO.getName() + "掉线");
                        break;
                    case 2:
                        log.warn(UserMonitorService.class, userMonitorVO.getName(), "监控用户：" + userMonitorVO.getName() + "队列深度异常");
                        break;
                    case 3:
                        log.info(UserMonitorService.class, userMonitorVO.getName(), "监控用户：" + userMonitorVO.getName() + "上线");
                        break;
                    case 4:
                        log.info(UserMonitorService.class, userMonitorVO.getName(), "监控用户：" + userMonitorVO.getName() + "下线");
                        break;
                }
            }
        } catch (Exception e) {
            log.error(UserMonitorServiceImpl.class, "userLogRecord() error", e);
        }

    }

    /**
     * 用户监控集合排序
     *
     * @param userMonitorVOs
     * @return
     */
    public List<UserMonitorVO> userMonitorVOSort(List<UserMonitorVO> userMonitorVOs) {
        try {
            //排序
            Collections.sort(userMonitorVOs, new Comparator<UserMonitorVO>() {
                @Override
                public int compare(UserMonitorVO o1, UserMonitorVO o2) {
                    if (o1.getState().compareTo(o2.getState()) == 0) {
                        return o1.getName().compareTo(o2.getName());
                    } else {
                        return o1.getState().compareTo(o2.getState());
                    }
                }
            });
        } catch (Exception e) {
            log.error(UserMonitorServiceImpl.class, "userMonitorVOSort()", e);
        }
        return userMonitorVOs;
    }

    /**
     * 获取CGW用户状态（从findAllUserMonitor（）中提取）
     * 2016-12-28 liuyi 创建
     *
     * @return
     */
    private Map<String, Object> getCGWUserStates() {
        Map<String, Object> result = null;
        List<UserMonitorVO> cgwUserSates = new ArrayList<>();

        try {
            Map<String, LinkedHashMap<String, String>> map = getRestService(sysConfigurationService.getValue(Constant.USER_MONITOR_URL));
            if (map != null) {
                result = new HashMap<>();
                LinkedHashMap<String, String> mapUserInfo = map.get("gwuser");

                Map<String, Map<String, LinkedHashMap<String, String>>> gwUserMap = new ObjectMapper().readValue(mapUserInfo.get("message"), Map.class);
                //模式
                String mode = new ObjectMapper().writeValueAsString(gwUserMap.get("mode")).replace("\"", "");
                result.put("mode", mode);

                Map<String, LinkedHashMap<String, String>> userListMap = gwUserMap.get("userList");//需判断普通模式还是应急模式
                Iterator iter = userListMap.entrySet().iterator();
                while (iter.hasNext()) {
                    UserMonitorVO userMonitorVO = new UserMonitorVO();
                    Map.Entry entry = (Map.Entry) iter.next();
                    //userid
                    userMonitorVO.setUserId((String) entry.getKey());
                    //CgwState
                    LinkedHashMap<String, String> map4 = (LinkedHashMap<String, String>) entry.getValue();
                    userMonitorVO.setCgwState(map4.get("state"));
                    //name
                    userMonitorVO.setName(map4.get("name"));
                    //ip
                    userMonitorVO.setIp(map4.get("ip"));
                    cgwUserSates.add(userMonitorVO);
                }
                result.put("cgwUserSates", cgwUserSates);
            }
        } catch (IOException e) {
            log.error(UserMonitorServiceImpl.class, "getCGWUserStates() error", e);
        }
        return result;
    }

    /**
     * 获取告警标识（从findAllUserMonitor（）中提取）
     * 2016-12-28 liuyi 创建
     *
     * @param sendQueueId
     * @param recvQueueId
     * @return
     */
    public Boolean checkQueueDepth(long sendQueueId, long recvQueueId) {
        // 发送队列深度
        long sendDepth = 0;
        // 接收队列深度
        long recDepth = 0;
        long MaxQueueDepth = 0;
        Boolean flag = false;

        try {
            //库里的队列最大深度
            Optional<Map<String, List<Map<String, String>>>> optional = sysConfigurationService.getSysConfigs();
            if (optional.isPresent()) {
                List<Map<String, String>> list = optional.get().get("Result");
                MaxQueueDepth = Long.parseLong(list.get(0).get(Constant.MQ_QUEUE_DEPTH).toString());
            }
            //MQ中队列深度
            Map<String, com.adcc.utility.mq.entity.Queue> map = getUserQueues(sendQueueId, recvQueueId);
            if (map != null) {
                sendDepth = map.get("sendQueue").getDepth();
                recDepth = map.get("recQueue").getDepth();

                //判断队列深度是否超阀值
                if (sendDepth > MaxQueueDepth || recDepth > MaxQueueDepth)
                    flag = true;
            }
        } catch (Exception e) {
            log.error(UserMonitorServiceImpl.class, "checkQueueDepth() error", e);
        }
        return flag;
    }

    /**
     * 获取用户接收队列、发送队列
     * 2017-01-09 liuyi 创建
     *
     * @param sendQueueId
     * @param recvQueueId
     * @return
     */
    public Map<String, com.adcc.utility.mq.entity.Queue> getUserQueues(long sendQueueId, long recvQueueId) {
        Map<String, com.adcc.utility.mq.entity.Queue> map = null;
        try {
            map = new HashMap<>();
            com.adcc.ags.gms.mq.entity.Queue sendQueue = queueService.findQueueById(sendQueueId);
            com.adcc.ags.gms.mq.entity.Queue recvQueue = queueService.findQueueById(recvQueueId);
            String sendQueueName = sendQueue.getName();
            String recvQueueName = recvQueue.getName();
            //MQserver中的队列深度
            MQManager mqManagerGW1 = mqFactory.getSourceMQM();
            List<com.adcc.utility.mq.entity.Queue> sendQueues = mqManagerGW1.findQueue(sendQueueName);
            List<com.adcc.utility.mq.entity.Queue> recQueues = mqManagerGW1.findQueue(recvQueueName);
            for (com.adcc.utility.mq.entity.Queue queue : sendQueues) {
                if (queue.getName().equals(sendQueueName)) {
                    map.put("sendQueue", queue);
                }
            }
            for (com.adcc.utility.mq.entity.Queue queue : recQueues) {
                if (queue.getName().equals(recvQueueName)) {
                    map.put("recQueue", queue);
                }
            }
        } catch (Exception e) {
            log.error(UserMonitorServiceImpl.class, "getUserQueues() error", e);
        }
        return map;
    }

    /**
     * 普通模式用户处理
     *
     * @param gwUser
     * @param CGWUsers
     * @return
     */
    public UserMonitorVO normalMode(GWUser gwUser, List<UserMonitorVO> CGWUsers) {
        UserMonitorVO userMonitorVO = new UserMonitorVO();
        try {
            Boolean flag = false;
            int effect = gwUser.getStatus();
            //本地上线
            if (effect == 1) {
                UserMonitorVO CGWUser = null;
                //匹配是否对应
                for (UserMonitorVO userMonitorVO1 : CGWUsers) {
                    //通过userid匹配
                    if (gwUser.getUserId().equals(userMonitorVO1.getUserId())) {
                        CGWUser = userMonitorVO1;
                        flag = true;
                        break;
                    }
                }
                if (flag) {//正常
                    if ("ONLINE".equals(CGWUser.getCgwState())) {
                        //判断队列深度是否超阀值
                        if (checkQueueDepth(gwUser.getSendQueueId(), gwUser.getRecvQueueId())) {
                            userMonitorVO.setState(2);//黄色
                            userMonitorVO.setMessage("告警,用户队列深度超阀值");
                        } else {
                            userMonitorVO.setState(3);//绿色
                            userMonitorVO.setMessage("在线");
                        }
                    } else if ("OFFLINE".equals(CGWUser.getCgwState())) {
                        userMonitorVO.setState(1);//红色
                        userMonitorVO.setMessage("掉线");
                    }
                    userMonitorVO.setIp(CGWUser.getIp());
                    userMonitorVO.setName(CGWUser.getName());
                } else {//异常
                    userMonitorVO.setState(1);
                    userMonitorVO.setMessage("掉线");
                    userMonitorVO.setName(gwUser.getUserName());
                }

            } else if (effect == 0) {//本地下线
                userMonitorVO.setState(4);
                userMonitorVO.setMessage("本地已下线");
                userMonitorVO.setName(gwUser.getUserName());
            }
            //获取用户发送队列和接收队列具体信息
            Map<String, com.adcc.utility.mq.entity.Queue> userQueues = getUserQueues(gwUser.getSendQueueId(), gwUser.getRecvQueueId());
            if (userQueues != null && userQueues.size() > 0) {
                com.adcc.utility.mq.entity.Queue sendQueue = userQueues.get("sendQueue");
                com.adcc.utility.mq.entity.Queue recQueue = userQueues.get("recQueue");
                userMonitorVO.setSendQueueName(sendQueue.getName());
                userMonitorVO.setSendQueueDepth(sendQueue.getDepth());
                userMonitorVO.setRecQueueName(recQueue.getName());
                userMonitorVO.setRecQueueDepth(recQueue.getDepth());
            }
        } catch (Exception e) {
            log.error(UserMonitorServiceImpl.class,"normalMode() error",e);
        }
        return userMonitorVO;
    }

    /**
     * 应急模式、CGW异常处理
     *
     * @param CGWUser
     * @param gwUser
     * @return
     */
    public UserMonitorVO emergencyMode(UserMonitorVO CGWUser, GWUser gwUser) {
        UserMonitorVO userMonitorVO = new UserMonitorVO();
        try {
            Map<String, com.adcc.utility.mq.entity.Queue> userQueues = getUserQueues(gwUser.getSendQueueId(), gwUser.getRecvQueueId());
            com.adcc.utility.mq.entity.Queue sendQueue = null;
            com.adcc.utility.mq.entity.Queue recQueue = null;
            if (CGWUser != null) {
                if ("ONLINE".equals(CGWUser.getCgwState())) {
                    //判断队列深度是否超阀值
                    if (checkQueueDepth(gwUser.getSendQueueId(), gwUser.getRecvQueueId())) {
                        userMonitorVO.setState(2);//黄色
                        userMonitorVO.setMessage("IP: " + CGWUser.getIp() + "告警,用户队列深度超阀值");
                    } else {
                        userMonitorVO.setState(3);//绿色
                        userMonitorVO.setMessage("IP: " + CGWUser.getIp() + "在线");
                    }
                } else if ("OFFLINE".equals(CGWUser.getCgwState())) {
                    userMonitorVO.setState(1);
                    userMonitorVO.setMessage("掉线");
                }
                userMonitorVO.setIp(CGWUser.getIp());
                userMonitorVO.setName(CGWUser.getName());
                //获取用户发送队列和接收队列具体信息
                if (userQueues != null && userQueues.size() > 0) {
                    sendQueue = userQueues.get("sendQueue");
                    recQueue = userQueues.get("recQueue");
                    userMonitorVO.setSendQueueName(sendQueue.getName());
                    userMonitorVO.setSendQueueDepth(sendQueue.getDepth());
                    userMonitorVO.setRecQueueName(recQueue.getName());
                    userMonitorVO.setRecQueueDepth(recQueue.getDepth());
                }
            } else {
                if (gwUser.getStatus() == 1) {
                    userMonitorVO.setState(1);
                    userMonitorVO.setMessage("掉线");
                } else if (gwUser.getStatus() == 0) {
                    userMonitorVO.setState(4);
                    userMonitorVO.setMessage("本地已下线");
                }
                userMonitorVO.setName(gwUser.getUserName());
                //获取用户发送队列和接收队列具体信息
                if (userQueues != null && userQueues.size() > 0) {
                    sendQueue = userQueues.get("sendQueue");
                    recQueue = userQueues.get("recQueue");
                    userMonitorVO.setSendQueueName(sendQueue.getName());
                    userMonitorVO.setSendQueueDepth(sendQueue.getDepth());
                    userMonitorVO.setRecQueueName(recQueue.getName());
                    userMonitorVO.setRecQueueDepth(recQueue.getDepth());
                }
            }
        } catch (Exception e) {
            log.error(UserMonitorServiceImpl.class,"emergencyMode() error",e);
        }
        return userMonitorVO;
    }

    /**
     * 取得rest接口服务状态
     *
     * @param url
     * @return
     */
    public static Map<String, LinkedHashMap<String, String>> getRestService(String url) {
        CloseableHttpClient client = null;
        CloseableHttpResponse response = null;
        try {
            HttpGet httpGet = new HttpGet(url);
            RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(5000).setConnectTimeout(5000).build();
            httpGet.setConfig(requestConfig);
            client = HttpClients.createDefault();
            response = client.execute(httpGet);
            if (response.getStatusLine().getStatusCode() == 200) {
                InputStream is = response.getEntity().getContent();
                Map<String, LinkedHashMap<String, String>> map = new ObjectMapper().readValue(CommonUtil.getString(is), Map.class);
                return map;
            } else {
                return null;
            }
        } catch (Exception ex) {
            Log.error(UserMonitorServiceImpl.class.getName(), "getRestService() error", ex);
            return null;
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
                if (client != null) {
                    client.close();
                }
            } catch (Exception e) {
                Log.error(UserMonitorServiceImpl.class.getName(), "close io error", e);
            }
        }
    }
}



